﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace Util
{
	[DefaultProperty("Text")]
	[ToolboxData("<{0}:AuthCode runat=server> </{0}:AuthCode>")]
	public class AuthCode : WebControl
	{
		[Bindable(true)]
		[Category("Appearance")]
		[DefaultValue(5)]
		[Localizable(true)]
		public int Line
		{
			get
			{
				object tp = ViewState["Line"];
				return tp == null ? 5 : Convert.ToInt32(tp);
			}
			set
			{
				ViewState["Line"] = value;
			}
		}

		[Bindable(true)]
		[Category("Appearance")]
		[DefaultValue(100)]
		[Localizable(true)]
		public int Point
		{
			get
			{
				int tp = Convert.ToInt32(ViewState["Point"]);
				return tp < 10 ? 50 : tp;
			}

			set
			{
				ViewState["Point"] = value;
			}
		}

		[Bindable(true)]
		[Category("Appearance")]
		[DefaultValue(16)]
		[Localizable(true)]
		public int Size
		{
			get
			{
				int tp = Convert.ToInt32(ViewState["Size"]);
				return tp < 10 ? 16 : tp;
			}

			set
			{
				ViewState["Size"] = value;
			}
		}

		public AuthCode()
		{
		}

		public bool Validate(string code)
		{
			return (code.ToUpper() == this.Page.Request.Cookies["validateCookie"].Values["ChkCode"].ToString().ToUpper());
		}

		public void CreateCode()
		{
			int _w = Convert.ToInt32(Width.Value);
			int _h = Convert.ToInt32(Height.Value);
			int _f = Convert.ToInt32((_h > Size ? Size : (_h < 10 ? 10 : _h)) * 0.9);
			HttpResponse resp = this.Page.Response;
			string chkCode = string.Empty;
			//颜色列表，用于验证码、噪线、噪点
			Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.DarkBlue };
			//字体列表，用于验证码
			string[] font = { "Times New Roman", "MS Mincho", "Book Antiqua", "Gungsuh", "PMingLiU", "Impact" };
			//验证码的字符集，去掉了一些容易混淆的字符
			char[] character ={ '2', '3', '4', '5', '6', '8', '9', 
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 
			'M', 'N', 'P', 'R', 'S', 'T', 'W', 'X', 'Y' };
			Random rnd = new Random();
			//生成验证码字符串
			for (int i = 0; i < 4; i++)
			{
				chkCode += character[rnd.Next(character.Length)];
			}
			//保存验证码的Cookie
			HttpCookie anycookie = new HttpCookie("validateCookie");
			anycookie.Values.Add("ChkCode", chkCode);
			resp.Cookies["validateCookie"].Values["ChkCode"] = chkCode;
			//定义这张图片
			Bitmap bmp = new Bitmap(_w, _h);
			Graphics g = Graphics.FromImage(bmp);
			g.Clear(Color.White);
			//画噪线
			for (int i = 0; i < Line; i++)
			{
				int x1 = rnd.Next(_w);
				int y1 = rnd.Next(_h);
				int x2 = rnd.Next(_w);
				int y2 = rnd.Next(_h);
				Color clr = color[rnd.Next(color.Length)];
				g.DrawLine(new Pen(clr), x1, y1, x2, y2);
			}
			//画噪点
			for (int i = 0; i < Point; i++)
			{
				int x = rnd.Next(bmp.Width);
				int y = rnd.Next(bmp.Height);
				Color clr = color[rnd.Next(color.Length)];
				bmp.SetPixel(x, y, clr);
			}
			//画验证码字符串
			for (int i = 0; i < chkCode.Length; i++)
			{
				int _l = chkCode.Length;
				int _dx = (_w - _l * _f / 2) / (_l * 4);
				int _dy = (_h - _f) / 4;
				string fnt = font[rnd.Next(font.Length)];
				Font ft = new Font(fnt, _f);
				Color clr = color[rnd.Next(color.Length)];
				g.DrawString(chkCode[i].ToString(), ft, new SolidBrush(clr), (float)(_w * i / _l + _dx), (float)_dy);
			}

			//将验证码图片写入内存流，并将其以"image/Png" 格式输出
			MemoryStream ms = new MemoryStream();
			try
			{
				bmp.Save(ms, ImageFormat.Png);
				resp.ClearContent();
				resp.ContentType = "image/Png";
				resp.BinaryWrite(ms.ToArray());
				resp.Flush();
				resp.End();
			}
			finally
			{
				//显式释放资源
				bmp.Dispose();
				g.Dispose();
			}
		}

		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);
			//开发环境设计视图
			if (this.DesignMode)
				return;
			//如果不是请求验证码
			string str = this.Page.Request.QueryString["_ImageTag"];
			if (str == "1")
			{
				this.CreateCode();//生成验证码
			}
		}


		protected override void Render(HtmlTextWriter output)
		{
			if (!this.DesignMode)
			{
				output.Write("<img border=\"0\" src=\"{0}\">", this.Page.Request.Path + "?_ImageTag=1");
				output.Write("&nbsp;<a href='#' onclick=" + Page.ClientScript.GetPostBackEventReference(this, string.Empty) + ">换一张</a>");
			}
			else
			{
				output.Write("验证码控件");
			}
		}
	}
}
